<?php
    defined('M2_MICRO') or die('Direct Access to this location is not allowed.');

    /**
      * @desc Class for database operations
      * @package M2 Micro Framework
      * @author Alexander Chaika
      */
    class Database extends Error {
        // instance
        private static $instance = null;

        private $cid;
        private $res;

        private $db_path;
        private $db_port;
        private $db_user;
        private $db_pass;
        private $db_base;
        private $db_prefix;

        private $query;

        /**
          * Database class constructor & clone
          * Use pattern singleton
          */
        private function __construct() {}
        private function __clone() {}

        /**
          * Return the instance of object
          * @param array $config (optional)
          */
        public static function getInstance() {
            // return instance
            if (null === self::$instance) {
                self::$instance = new self();
            }
            return self::$instance;
        }
        
        /**
          * Connect to DB and select TABLE
          * @return bool $state
          */
        public function connect($config = null) {
            if (!empty($config)) {
                $this->db_path = $config['db_path'];
                $this->db_port = $config['db_port'];
                $this->db_user = $config['db_user'];
                $this->db_pass = $config['db_pass'];
                $this->db_base = $config['db_base'];
                $this->db_prefix = $config['db_prefix'];
            }

            $this->cid = mysql_pconnect($this->db_path.':'.$this->db_port, $this->db_user, $this->db_pass);
            if (!$this->cid) {
                return $this->throwError($this->getLastErrorMsg());
            }

            if (!mysql_select_db($this->db_base, $this->cid)) {
                return $this->throwError($this->getErrorString());
            }

            return $this->cid;
        }

        /**
          * Close connection to DB
          * @return bool $state
          */
        public function close() {
            if (!mysql_close($this->cid)) {
                return $this->throwError($this->getErrorString());
            } else {
                return $this->cleanError();
            }
        }

        /**
          * Replace #__ to db prefix
          * @param string $query
          * @return string $db_table with prefix
          */
        private function replacePrefix($query) {
            return str_replace('#__', $this->db_prefix, $query);
        }

        /**
          * Set and execute query
          * if success return number of affected rows or false
          * !write the names of all tables without the prefix, but like #__
          * @param string $query
          * @return bool $state
          */
        public function query($query) {
            $this->query = $this->replacePrefix($query);
            $this->res = mysql_query($this->query, $this->cid);

            if (mysql_error() != '') {
                return $this->throwError($this->getErrorString());
            } else {
                $this->_last_result = mysql_affected_rows();
                return $this->_last_result;
            }
        }

        /**
          * Execute last query
          * @return executing $state
          */
        public function exec() {
            if (!empty($this->query)) {
                return $this->query($this->query);
            } else {
                return $this->throwError('Query is empty!');
            }
        }

        /**
          * Set query
          * @param string $query (optional)
          * @return bool $state
          */
        public function setQuery($query = null) {
            if (!empty($query)) {
                $this->query = $query;
                return $this->cleanError();
            } else {
                return $this->throwError('Query is empty!');
            }
        }

        /**
          * Get last query
          * @return string $query or false
          */
        public function getQuery() {
            if (!empty($this->query)) {
                return $this->query;
            } else {
                return $this->throwError('Query is empty!');
            }
        }

        /**
          * Print last query
          */
        public function printQuery() {
            $query = $this->getQuery();
            $query = (empty($query) ? 'No queries executed' : $this->replacePrefix($query));
            echo '<pre>' . $query . '</pre>';
        }

        /**
          * Get first field value of result
          * @param mixed $pattern
          * @return string $result
          */
        public function getResult() {
            if ($this->_last_result < 1) {
                if ($this->getLastErrorNum() > 0) return $this->throwError($this->getErrorString());
                else return false;
            }

            $row = mysql_fetch_row($this->res);
            if (!$row || empty($row)) return false;
            else return $row[0];
        }

        /**
          * Get first resulting object of query
          * @param object $pattern
          * @return object $result
          */
        public function getObject() {
            if ($this->_last_result < 1) {
                if ($this->getLastErrorNum() > 0) return $this->throwError($this->getErrorString());
                else return false;
            }

            $obj = mysql_fetch_object($this->res);
            if (!$obj || empty($obj)) return false;
            else return $obj;
        }

        /**
          * Get result objects array of query
          * @param object $pattern
          * @return objects array $result
          */
        public function getObjectsArray() {
            if ($this->_last_result < 1) {
                if ($this->getLastErrorNum() > 0) return $this->throwError($this->getErrorString());
                else return false;
            }

            while($obj = mysql_fetch_object($this->res)) {
                if (!$obj || empty($obj)) break;
                $arr[] = $obj;
            }
            return $arr;
        }

        /**
          * Get result array of query
          * @return array $result
          */
        public function getArray() {
            if ($this->_last_result < 1) {
                if ($this->getLastErrorNum() > 0) return $this->throwError($this->getErrorString());
                else return false;
            }

            while($row = mysql_fetch_array($this->res, MYSQL_NUM)) {
                if (!$row || empty($row)) break;
                $arr[] = $row[0];
            }
            return $arr;
        }

        /**
          * Get array of named pairs
          * @return array $result
          */
        public function getPairs($index, $field) {
            if ($this->_last_result < 1) {
                if ($this->getLastErrorNum() > 0) return $this->throwError($this->getErrorString());
                else return false;
            }

            while($obj = mysql_fetch_object($this->res)) {
                if (!$obj || empty($obj)) break;
                if (empty($obj->$index)) {
                    return $this->throwError('Incorrect index!');
                }
                $arr[(int)$obj->$index] = $obj->$field;
            }
            return $arr;
        }

        /**
          * Get last error string with error number
          * @return string $error
          */
        public function getErrorString() {
            return mysql_errno().': '.mysql_error();
        }

        /**
          * Get last error message
          * @return string $error
          */
        public function getLastErrorMsg() {
            return mysql_error();
        }

        /**
          * Get last error number
          * @return int $error_number
          */
        public function getLastErrorNum() {
            return (int)mysql_errno();
        }

        /**
          * Get last insert id
          * @return int $id
          */
        public function getLastInsertId() {
            return (int)mysql_insert_id($this->cid);
        }
    }

    // global object
    $GLOBALS['database'] = Database::getInstance();
?>
